const arr = [1, 2, 3, 4, 4]

console.log(arr.includes(2))

// 指数运算 Math.pow()
console.log(Math.pow(2, 3))
// ES7 => [**] <=> Math.pow()
console.log(2 ** 3)

// ES8;
// 对 Object 快速遍历；

const grade = {
  a: 88,
  b: 8
}

console.log(Object.keys(grade)) // ["a", "b"]

console.log(Object.values(grade)) // [88, 8]

console.log(Object.entries(grade)) // [[k, v], [k, v]]

// 正则处理中文字符
// ES5 => ES5 中不支持 4 个字节的中文字符， 不能使用那个 Unicode 范围
// ES6 => u 标识符可以正确识别 4 字节的中文字符

// 字符编码
/*
  ES6 中多字节的识别， 正则的 U 修饰符， 来识别 Unicode 编码, 大于 \uffff 这个 unicode 的都是可以识别的

  Unicode => U+20BBF(𠮷)
*/
let str = '𠮷'
let s2 = '\uD842\uDFB7' // 四个字节(utf-16),
console.log(/^\uD842/.test(s2)) // true 如果不添加 u， 这个正则的匹配是不准确的， 因为 s2 这个 Unicode 是标识的是一个字符 '𠮷'，但是来匹配的时候却是 true
console.log(/^\uD842/u.test(s2)) // false, 这个是正确的表示的， 存在中文都需要添加到 u 标识

// ES5
console.log(/^.$/.test(str)) // false, 点 的通配符也是不能匹配到 4 字节点中文字符
// ES6
console.log(/^.$/u.test(str)) // true， 添加 u 标识之后可以

console.log(/\u{20bb7}/u.test(str)) // \u{xxxx} 能够正确匹配到中文的字符， 包含了 4 个字节的字符, 可以匹配到旧的 Unicode 的写法

// 量词
console.log(/𠮷{2}/u.test('𠮷𠮷'))// true, 去掉 u, 就是 false

// 正则 y 修饰符
let s = 'aaa_aa_a'
const r1 = /a+/g
const r2 = /a+/y

// 第一次
console.log(r1.exec(s)) // 匹配到 aaa，index：0
console.log(r2.exec(s)) // 匹配到 aaa，index：0

// 第二次
console.log(r1.exec(s)) // 匹配到 aa， index： 4
console.log(r2.exec(s)) // null

// y 表示是 => sticky 粘连

// 字符串中补白
console.log('10'.padStart(9, '0x'))
console.log('xx'.padEnd(5, 'jjj'))

// 异步循环函数
function gen(time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(time)
    }, time)
  })
}

async function test() {
  let arr = [gen(100), gen(200), gen(300)]
  for (let item of arr) {
    console.log(Date.now())
    await item.then(console.log)
  }
}

// test()

// 使用 for await ... of ...

async function fn() {
  let arr = [gen(100), gen(200), gen(300)]
  for await (let item of arr) {
    console.log(Date.now(), item, "fuck")
  }
}

// ;fn()

const obj = {
  count: 0,
  gen(time) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve({ done: false, value: time })
      }, time)
    })
  },
  // 配合 for await (let item of list) {...} 要遵守这个规则
  [Symbol.asyncIterator]() {
    let self = this
    return {
      // next 是一个迭代器的规则协议
      next() {
        self.count++
        if (self.count < 4) {
          return self.gen(Math.random() * 1000)
        } else {
          // 这里要遵守迭代器对象的规则：返回对象中有一个 done 和 value 字段 { down: true, value: '' }
          // done 为 true 的话，那么就迭代完成
          return Promise.resolve({ done: true, value: '' })
        }
      }
    }
  }
}

async function testFn() {
  // obj 是一个迭代器的遍历， 因为内部实现了迭代器的规则
  for await (let item of obj) {
    console.log(item, "enter")
  }
}

// testFn()

// ES9 中的 Promise 的兜底操作 finally
function gen1(time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (time < 0.5) {
        reject(time)
      } else {
        resolve(time)
      }

    }, time)
  })
}

// gen(Math.random() * 1000).then((time) => {
//   console.log(time, "ok")
// }).catch((err) => {
//   console.log(err, "err")
// }).finally(() => {
//   console.log("finally")
// })


// RegExp : dotAll, 命名分组捕获，后行断言，

// 正则中的 点 不能够匹配任意字符， 如： 4字节的 utf-16 的字符， 和行终止符(\r\n)
console.log(/for.bar/.test('forabar')) // true
console.log(/for.bar/.test('for\nbar')) // false
console.log(/for.bar/s.test('for\nbar')) // true
console.log(/for.bar/.test('for\r\nbar')) // false
// s 标示 dotAll 模式
console.log(/for.bar/s.test('for\r\nbar'))
console.log(/for.bar/s.dotAll) // true => 开启了 dotAll 模式

console.log(/for.bar/.dotAll) // false
console.log(/for.bar/sugi.flags) // 输出正则的输出符

// 匹配 年份， 月份， 日期
console.log('2019-06-07'.match(/(\d{4})-(\d{2})-(\d{2})/)) // =>  ["2019-06-07", "2019", "06", "07", index: 0, input: "2019-06-07", groups: undefined]
// match => 第一个是完整的匹配， 接着是小括号的分组， index 从哪里开始匹配， input 标示完整的字符串， groups

// ES9 中给正则中分组定义 name；
const r = '2019-06-07'.match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/)
/*
["2019-06-07", "2019", "06", "07", groups: {year: "2019", month: "06", day: "07"}, index: 0, input: "2019-06-07"]
*/
console.log(r) // 这里可以从 groups 中获取到分组的对象

// 正则中的先行断言，后行断言
let str1 = 'hello world'
let str2 = 'hello world'

console.log(str1.match(/hello(?=\sworld)/)) // 先行断言， 先遇到符合要求的， 再去判断后面的是否是匹配的
console.log(str1.match(/hello(?!\sworld)/)) // 先行断言， 先遇到符合要求的， 再去判断后面的是否是匹配的
console.log(str2.match(/(？<=hello\s)world/)) // 后行断言，如果遇到符合要求的，需要判断后面的是否符合要求, 匹配到 world 时，需要看一下 world 前面是否是 hello
console.log(str2.match(/(？<!hello\s)world/)) // 后行断言的符合 ?= 等于，？! 不等于

// JSON.stringify() => 0xD800 - 0xDFFF 中的字符，由于无法编译为utf8, 导致转义失败
console.log(JSON.stringify('\u{d800}'))

// 扁平化输出 list.flat() ,有一个深度的参数 depth
let list = [1, [1, 2, 3], [3, 4, [2, 11]]]
console.log(list.flat(3)) // 合并成一个新的数组放回,

let list1 = [2, 3, 4, [1, 3]]

// arr.flatMap()
console.log(list1.flatMap((item) => {
  console.log(item)
  return item
}))

//
let strings = "   foo   "
console.log()
// match 如果使用了 g 修饰符， 只会返回匹配内容的数组

// strings.matchAll(/"[^"]*"/)

let list3 = [['a', 1], ['b', 2]]

console.log(Object.fromEntries(list3))

// BigInt 大数字, 处理超过 2**53 的数字
